package com.anyext.storage.group.impl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.springframework.beans.factory.InitializingBean;

import com.anyext.storage.StorageContext;
import com.anyext.storage.RouterHolder;
import com.anyext.storage.dialect.Dialect;
import com.anyext.storage.group.GroupDescriptor;
import com.anyext.storage.group.Group;
import com.anyext.storage.lb.LBRound;
import com.anyext.storage.lb.RoundCard;
import com.anyext.storage.policy.DataSourceType;
import com.anyext.storage.router.Router;

public class GroupImpl implements Group, InitializingBean {
	
	private String identity;
	
	private Dialect dialect;
	
	private Router router;
	
	private Map<String, GroupDescriptor> groupDescriptors;

	private Map<String, GroupDescriptor> masterGroup;
	
	private Map<String, GroupDescriptor> slaveGroup;

	private Map<DataSourceType, RoundCard<GroupDescriptor>> groupRoundCard;
	
	public void setIdentity(String identity) {
		this.identity = identity;
	}

	@Override
	public String getIdentity() {
		return this.identity;
	}

	public void setDialect(Dialect dialect) {
		this.dialect = dialect;
	}
	
	@Override
	public Dialect getDialect() {
		return this.dialect;
	}

	public void setRouter(Router router) {
		this.router = router;
	}

	@Override
	public Router getRouter() {
		return this.router;
	}

	@Override
	public GroupDescriptor getRoutingGroupDescriptor() {
		RoundCard<GroupDescriptor> roundCard = this.groupRoundCard.get(RouterHolder.getDataSourceType());
		if(roundCard == null) return null;
		return roundCard.getCard();
	}

	@Override
	public GroupDescriptor getGroupDescriptor(String identity) {
		return this.groupDescriptors.get(identity);
	}

	@Override
	public Map<String, GroupDescriptor> getGroupDescriptors() {
		return this.groupDescriptors;
	}

	@Override
	public Map<String, GroupDescriptor> getGroupDescriptors(DataSourceType type) {
		switch (type) {
			case Master	: return this.masterGroup;
			case Slave	: return this.slaveGroup;
			default 	: return null;
		}
	}

	public void setGroupDescriptors(Map<String, GroupDescriptor> groupDescriptors) {
		this.groupDescriptors = groupDescriptors;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if(this.groupDescriptors != null) {
			this.masterGroup = new HashMap<String, GroupDescriptor>();
			this.slaveGroup = new HashMap<String, GroupDescriptor>();
			this.groupRoundCard = new HashMap<DataSourceType, RoundCard<GroupDescriptor>>();
			for(GroupDescriptor descriptor : this.groupDescriptors.values()) {
				switch(descriptor.getDataSourceType()) {
					case Master	: this.masterGroup.put(descriptor.getIdentity(), descriptor);
					case Slave	: this.slaveGroup.put(descriptor.getIdentity(), descriptor);
				}
			}
			setUpLoadBalance(DataSourceType.Master);
			setUpLoadBalance(DataSourceType.Slave);
		}
		StorageContext.addGroupName(this.identity);
	}
	
	private void setUpLoadBalance(DataSourceType type) {
		Map<String, GroupDescriptor> descriptors = getGroupDescriptors(type);
		if(descriptors.size() > 0) {
			RoundCard<GroupDescriptor> roundCard = new LBRound<GroupDescriptor>();
			Iterator<GroupDescriptor> iterator = descriptors.values().iterator();
			while(iterator.hasNext()) {
				GroupDescriptor descriptor = iterator.next();
				roundCard.add(descriptor, descriptor.getLbfactor());
			}
			roundCard.apply();
			this.groupRoundCard.put(type, roundCard);
		}
	}

}
